package com.zx.flow.core.engine;

import cn.hutool.extra.spring.SpringUtil;
import com.zx.flow.api.config.FlowConfig;
import com.zx.flow.api.config.FlowConfigCheckHandler;
import com.zx.flow.api.dict.FlowDict.StorageType;
import com.zx.flow.api.exception.FlowException;
import com.zx.flow.api.execute.model.FlowContext;
import com.zx.flow.api.execute.request.FlowParam;
import com.zx.flow.api.execute.response.FlowResult;
import com.zx.flow.api.util.AssertUtil;
import com.zx.flow.core.cache.EventHandlerCache;
import com.zx.flow.core.cache.FlowConfigCache;
import com.zx.flow.core.cache.SecretCache;
import com.zx.flow.core.execute.EventHandler;
import com.zx.flow.core.service.FlowTraceService;
import com.zx.flow.db.FlowStorageDBHandler;
import com.zx.flow.db.FlowStorageHandler;
import com.zx.flow.db.FlowStorageMockHandler;
import com.zx.flow.db.entity.FlowSecretEntity;
import java.util.List;
import java.util.Objects;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

/**
 * 流程引擎
 */
@Slf4j
@Data
public class FlowEngineImpl implements FlowEngine {

    private StorageType storageType;

    /**
     * 根据 storageType 实例化不同类型的 storageHandler
     */
    private FlowStorageHandler storageHandler;

    @Override
    public synchronized void init() throws Exception {
        log.info("FlowEngine init, StorageType={}", this.storageType);
        // 初始化流程文件校验器
        FlowConfigCheckHandler.init();
        // 初始化事件处理器
        EventHandlerCache.init();

        // 设置存储处理器
        if (Objects.equals(this.storageType, StorageType.mock)) {
            this.storageHandler = new FlowStorageMockHandler();
        } else if (Objects.equals(this.storageType, StorageType.db)) {
            // db操作类，从spring中获得
            this.storageHandler = SpringUtil.getBean(FlowStorageDBHandler.class);
        } else {
            throw new FlowException("暂不支持, storageType=" + storageType);
        }

        // 加载流程配置&添加至缓存
        List<FlowConfig> allFlowConfig = this.storageHandler.getAllFlowConfig();
        allFlowConfig.forEach(FlowConfigCache::put);

        // 初始化安全校验
        List<FlowSecretEntity> secret = this.storageHandler.getSecret();
        secret.forEach(SecretCache::put);
    }

    @Override
    public FlowResult execute(FlowParam param) {
        // 获得流程对象，可能为null,比如第一次创建的时候
        FlowContext flow = this.storageHandler.getFlow(param.getId());
        // 获得事件处理器
        EventHandler handler = EventHandlerCache.getHandler(param.getClass());
        // 发布事件[publicEvent不会抛出异常，只会返回成功、失败、异常等三种状态]
        FlowResult flowResult = handler.publicEvent(this, flow, param);
        log.info("流程引擎, 执行事件处理, handler={}, param={}, flowResult={}",
                handler.getClass().getSimpleName(), param.toString(), flowResult.toString());

        // 记录链路信息
        FlowTraceService.trace(param, flowResult);

        // 统一再次验证每次事件执行结果
        AssertUtil.checkFlowResult(flowResult);
        return flowResult;
    }

    @Override
    public FlowStorageHandler getStorageHandler() {
        return this.storageHandler;
    }

}
